package com.monitor.service;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;




import com.jfinal.log.Logger;
import com.monitor.exception.MonitorException;
import com.monitor.exception.TimeOutException;
import com.monitor.model.Log;
import com.monitor.model.Record;
import com.monitor.model.Sensor;
import com.monitor.model.Warning;
import com.monitor.utils.DateUtil;

public class MonitorServerSocket {
	private static Logger logger = Logger.getLogger(MonitorServerSocket.class);
	private ServerSocket serverSocket;
	private int port;
	private Warning warning = new Warning();
	private MonitorDataThread dateThread = new MonitorDataThread(warning);
	ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

	/**
	 * 正常溫度
	 */
	private int normalTemperature;

	/**
	 * 正常湿度
	 */
	private int normalHumidity;
	
	/**
	 * 监控线程苏醒的间隔时间 单位 min
	 */
	private int interval;

	public MonitorServerSocket(int port, int normalTemperature,
			int normalHumidity,int interval) {
		this.port = port;
		this.normalHumidity = normalHumidity;
		this.normalTemperature = normalTemperature;
		this.interval = interval;
	}

	/**
	 * 监听端口
	 * 
	 * @return Socket
	 * @throws MonitorException
	 */
	public Socket accrept() throws MonitorException {
		try {
			serverSocket = new ServerSocket(port);
			logger.info("服务器开始在" + port + "端口监听");
			return serverSocket.accept();
		} catch (IOException e) {
			// TODO 这里需要处理异常
			e.printStackTrace();
			logger.error("服务器开启失败");
			throw new MonitorException("服务器开启失败");
		}
	}

	/**
	 * 从socket中读取记录 先按*分成每個节点的数据字符串 
	 * #qwer#21#34#0*#asdf#23#36#0*#zxcv#22#38#0*
	 * #00124B00A#27#21#0
	 * @param socket
	 * @return
	 * @throws TimeOutException
	 */
	public void getRecord(Socket socket) throws TimeOutException,
			MonitorException {
		logger.info("开始接受数据");
		
		
		// 这里设置成5分钟后开始执行监控线程，以后每隔5分钟执行
		// TODO 把监控线程循环苏醒的时间改成从配置文件里读取
		//修改线程池的执行方式来测试会不会在监控线程运行之后就读不到数据 要重启serversocket 20150510 191103
		//executor.scheduleWithFixedDelay(dateThread, 5, interval, TimeUnit.MINUTES);

		executor.scheduleAtFixedRate(dateThread, 5, interval, TimeUnit.MINUTES);
		Sensor sensor = new Sensor();
		char[] data = new char[1000];
		int clientOn;
		try {
			InputStreamReader reader = new InputStreamReader(
					socket.getInputStream(), "UTF-8");

			while ((clientOn = reader.read()) != -1) {
				// 当读取的数据为-1时说明客户端已经关闭，抛出TimeOut异常，让服务器重新开始接受socket连接

				logger.info("已读取到数据");
				
				reader.read(data);
				String DataStr = "#" + new String(data).trim(); // 补上已经被读取掉的#
				logger.info("原始数据："+DataStr);
				// TODO 监控线程也从这里开始运行
				// 先按*切割（要写成\\*）分成每个节点单独的顺序
				for (String recordStr : DataStr.split("\\*", 0)) {
					logger.debug("分割后数据字符串：" + recordStr);
					if(recordStr.length() != "#00124B00A#27#21#0".length() ){
						logger.info("接收到的数据长度不正确");
						//Log.me.saveMsg("接收到的数据长度不正确");
						continue;
					}
					boolean flag = false;
					String[] recordArray = recordStr.split("#", 0);
					
					//由于传输过程中数据丢失和错位严重，所以把节点的网络地址存入数据库，然后直接判断接受的数据里的节点地址
					//在不在数据库里，由此来判断数据是否无误
					// 得到传感器的物理地址
					int sensorId = sensor.findByName(recordArray[1]);	
					if(sensorId == 0){
						logger.info("接收到的节点地址不存在");
						Log.me.saveMsg("接收到的节点地址不存在");
						continue;
					}
					// 先判断是不是危险值，再放在normal和warningMap里面 再按正常值和危险值存数据库
					if(recordArray[1].equals("FF")||recordArray[2].equals("FF")){
						continue;
					}
					// 判断温度
					if (Integer.parseInt(recordArray[2]) > normalTemperature) {
						logger.info("危险温度");
						warning.getWarn().put(Sensor.sensor.findById(sensorId),
								new Date());
						warning.getTemperature().put("temp", Integer.parseInt(recordArray[2]));
						flag = true;
					}
					// 湿度
					if (Integer.parseInt(recordArray[3]) < normalHumidity) {
						logger.info("危险湿度");
						warning.getWarn().put(Sensor.sensor.findById(sensorId),
								new Date());
						warning.getTemperature().put("temp", Integer.parseInt(recordArray[2]));
						flag = true;
					}
					// 烟雾
					if (recordArray[4].equals("1")) {
						logger.info("危险烟雾");
						warning.getWarn().put(Sensor.sensor.findById(sensorId),
								new Date());
						warning.getTemperature().put("temp", Integer.parseInt(recordArray[2]));
						flag = true;
					}
					// 保存到normalMap
					warning.getNormal().put(Sensor.sensor.findById(sensorId),
							new Date());

					// 保存数据

					if (flag) {
						saveRecord(sensorId, recordArray, 1);
					} else {
						saveRecord(sensorId, recordArray, 0);
					}

				}
				
			}
			if (clientOn == -1) {
				logger.error("*********读取超时*******");
				throw new TimeOutException("TimeOutException");
			}
		} catch (IOException e) {
			
			logger.error("读取数据时发生不可处理的异常");
			throw new MonitorException("读取数据时发生不可处理的异常 IOException");
		}catch (Exception e ) {
			 //其他不可以预知的异常在这里处理
			if(e.getMessage().equals("TimeOutException")){
				throw new TimeOutException("客户端关闭");
			}else{
				e.printStackTrace();
				//这里注释掉抛出MonitorException 因为在日志里抛出这样的异常之后服务器依然可以启动成功 2015-05-10 17.59.00
				//throw new MonitorException("读取数据时发生不可处理的异常");
			}
			
		}
		

	}

	/**
	 * 保存记录
	 * 
	 * @param records
	 */
	public void saveRecord(int sensorId, String[] recordArr, int warning) {
		logger.debug("-----保存数据开始----");
		new Record().set("sensorId", sensorId).set("temperature", recordArr[2])
				.set("humidity", recordArr[3]).set("smoke", recordArr[4])
				.set("warning", warning)
				.set("recordTime", DateUtil.getDateNow())
				.save();
		logger.debug("-----保存数据结束----");
	}

	public void close() throws IOException {
			// 关闭serverSocket的同时关掉监控线程
			executor.shutdownNow();
			executor = Executors.newScheduledThreadPool(5);
			serverSocket.close();
			logger.info("服务端关闭socket,停止监控线程");
		
	
	}
}
